﻿// ServerTimeSync.ts
const { ccclass } = cc._decorator;

/**
 * 服务器时间同步管理器
 * 提供高精度服务器时间，支持自动校准
 */
@ccclass
export class ServerTimeSync extends cc.Component {
  private static _instance: ServerTimeSync | null = null;

  public static get instance(): ServerTimeSync {
    if (!ServerTimeSync._instance) {
      const node = cc.director.getScene().getChildByName("ServerTimeSync");
      if (!node) {
        const newNode = new cc.Node("ServerTimeSync");
        cc.director.getScene().addChild(newNode);
        ServerTimeSync._instance = newNode.addComponent(ServerTimeSync);
      } else {
        ServerTimeSync._instance =
          node.getComponent(ServerTimeSync) ||
          node.addComponent(ServerTimeSync);
      }
    }
    return ServerTimeSync._instance;
  }

  onLoad() {
    if (ServerTimeSync._instance && ServerTimeSync._instance !== this) {
      this.destroy();
      return;
    }
    ServerTimeSync._instance = this;
  }

  onDestroy() {
    ServerTimeSync._instance = null;
  }

  // ======================== 时间同步核心 ========================

  /**
   * 服务器时间偏移量（毫秒）
   * 客户端时间 + offset = 服务器时间
   */
  private _timeOffset: number = 0;

  /**
   * 最后一次同步时间（本地时间戳，毫秒）
   */
  private _lastSyncTime: number = 0;

  /**
   * 同步周期（毫秒），默认 300 秒同步一次
   */
  private _syncInterval: number = 300 * 1000;

  /**
   * 是否已同步
   */
  private _isSynced: boolean = false;

  // ======================== 公共 API ========================

  /**
   * 获取当前服务器时间戳（毫秒）
   * @returns 服务器时间（毫秒）
   */
  public getServerTime(): number {
    const localNow = Date.now();
    return localNow + this._timeOffset;
  }

  /**
   * 获取服务器时间的 Date 对象
   */
  public getServerDate(): Date {
    return new Date(this.getServerTime());
  }

  /**
   * 是否已经完成过一次时间同步
   */
  public get isSynced(): boolean {
    return this._isSynced;
  }

  /**
   * 开始时间同步（建议在登录后调用）
   * @param serverTimeUrl 服务器时间接口 URL
   * @param syncInterval 同步间隔（毫秒），默认 5 分钟
   */
  public startSync(
    serverTimeUrl: string,
    syncInterval: number = 300 * 1000
  ): void {
    this._syncInterval = syncInterval;
    this.syncWithServer(serverTimeUrl).then(() => {
      // 同步成功后，启动定时器定期校准
      this.unschedule(this._autoSyncTask);
      this.schedule(this._autoSyncTask, this._syncInterval / 1000);
    });
  }

  /**
   * 手动强制同步一次
   * @param serverTimeUrl
   */
  public async syncWithServer(serverTimeUrl: string): Promise<void> {
    const startTime = Date.now();

    try {
      const response = await fetch(serverTimeUrl, {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
        },
      });

      const data = await response.json();

      // 假设服务器返回 { "serverTime": 1712345678901 } // 毫秒时间戳
      const serverTime = data.serverTime;
      if (typeof serverTime !== "number") {
        throw new Error("Invalid serverTime format");
      }

      const endTime = Date.now();
      const rtt = endTime - startTime; // 往返延迟
      const estimatedServerTime = endTime - rtt / 2;

      this._timeOffset = serverTime - estimatedServerTime;
      this._lastSyncTime = endTime;
      this._isSynced = true;

      console.log(
        `[ServerTimeSync] Synced! Offset: ${this._timeOffset}ms, RTT: ${rtt}ms`
      );
    } catch (error) {
      console.error("[ServerTimeSync] Sync failed:", error);
      // 即使失败也保留上次偏移量（降级处理）
    }
  }

  /**
   * 自动同步任务
   */
  private _autoSyncTask() {
    const serverTimeUrl = (window as any).__SERVER_TIME_URL__; // 你可以通过构建配置注入
    this.syncWithServer(serverTimeUrl);
  }

  /**
   * 计算距离服务器时间某个时间点的剩余秒数
   * @param targetTime 服务器时间戳（毫秒）
   * @returns 剩余秒数（向下取整）
   */
  public getRemainingSeconds(targetTime: number): number {
    const remaining = Math.floor((targetTime - this.getServerTime()) / 1000);
    return Math.max(0, remaining);
  }

  /**
   * 格式化服务器时间为 HH:mm:ss
   */
  public formatTime(date: Date = this.getServerDate()): string {
    return date.toISOString().substr(11, 8);
  }

  /**
   * 格式化服务器时间为 yyyy-MM-dd HH:mm:ss
   */
  public formatDate(date: Date = this.getServerDate()): string {
    return date.toLocaleString("zh-CN", { hour12: false }).replace(/\//g, "-");
  }
}

//-----------------------使用示例-------------------------

// import { ServerTimeSync } from "utils/ServerTimeSync";

// // 登录后启动同步
// ServerTimeSync.instance.startSync(
//   "https://your-api.com/api/server-time",
//   300 * 1000
// );

// // 获取服务器时间
// const serverTime = ServerTimeSync.instance.getServerTime(); // 毫秒
// const serverDate = ServerTimeSync.instance.getServerDate();

// // 倒计时示例：活动在 2025-09-30 10:00:00 结束
// const endTime = new Date("2025-09-30T10:00:00+08:00").getTime();
// const remaining = ServerTimeSync.instance.getRemainingSeconds(endTime);
// console.log(`距离活动结束还有 ${remaining} 秒`);

// // 格式化显示
// console.log("当前服务器时间:", ServerTimeSync.instance.formatDate());

//-----------------------服务器接口示例-----------------------
// server.js
// app.get("/api/server-time", (req, res) => {
//   res.json({
//     serverTime: Date.now(), // 返回当前服务器时间戳（毫秒）
//   });
// });
